package org.myspringframework.beans.factory.support;

import org.myspringframework.beans.BeansException;
import org.myspringframework.beans.factory.ConfigurableBeanFactory;
import org.myspringframework.beans.factory.FactoryBean;
import org.myspringframework.beans.factory.config.FactoryBeanRegistrySupport;
import org.myspringframework.beans.factory.config.beandefinition.BeanDefinition;
import org.myspringframework.beans.factory.config.postprocessor.BeanPostProcessor;
import org.myspringframework.beans.factory.config.DefaultSingletonBeanRegistry;
import org.myspringframework.context.annotation.Autowired;
import org.myspringframework.utils.StringValueResolver;

import java.util.ArrayList;
import java.util.List;

//实现了获取bean的方法，保存了beanpostprocessor，
//继承了DefaultSingletonBeanRegistry能够获取单例bean
//继承了FactoryBeanRegistrySupport，能够获取factroyBean的getObject()方法创建的object集合
//抽象类-模板方法模式
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

    /** BeanPostProcessors集合 */
    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
    /** 如有必要，使用ClassLoader解析bean类名 */
    private ClassLoader beanClassLoader = Thread.currentThread().getContextClassLoader();
    /**字符串解析器应用于注释属性值*/
    private final List<StringValueResolver> embeddedValueResolvers = new ArrayList<>();

    //根据BeanName获取Bean
    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return (T) getBean(name);
    }


    protected <T> T doGetBean(final String name, final Object[] args) {
        Object bean;
        //尝试从singletion集合中获取单例bean
        Object singletonBean = getSingleton(name);
        if (singletonBean != null) {
            //判断该bean是否为factroyBean,如果是，则应该放回他getObject()方法对应的object
            return (T) getObjectForBeanInstance(singletonBean,name);
        }

        //singletion集合中不存在，需要创建bean
        BeanDefinition beanDefinition = getBeanDefinition(name);
        if (beanDefinition.isSingleton()){
            //为单例bean
            Object sharedInstance = this.getSingleton(name, () -> {
                return this.createBean(name, beanDefinition, args);
            });
            //判断该bean是否为factoryBean,如果是，则应该放回他getObject()方法对应的object
            bean=getObjectForBeanInstance(sharedInstance,name);
        }else{
            //为原型bean
            Object propertyInstance=this.createBean(name,beanDefinition,args);
            //判断该bean是否为factoryBean,如果是，则应该放回他getObject()方法对应的object
            bean=getObjectForBeanInstance(propertyInstance,name);
        }

        return (T)bean;
    }

    //判断该bean是否为factroyBean,如果是，则应该放回他getObject()方法对应的object
    private Object getObjectForBeanInstance(Object beanInstance, String beanName) {
        //判断是否为FactoryBean
        if (!(beanInstance instanceof FactoryBean)) {
            //不是，直接返回
            return beanInstance;
        }

        //是factoryBean,尝试从缓存中取
        Object object = getCachedObjectForFactoryBean(beanName);
        if (object == null) {
            //缓存中没有，使用factoryBean的getObject（）方法创建
            FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;
            object = getObjectFromFactoryBean(factoryBean, beanName);
        }

        return object;
    }

    @Override
    public Class<?> getType(String beanName){
        return this.getBeanDefinition(beanName).getBeanClass();
    }

    //抽象方法:根据name获取BeanDefinition
    protected abstract  BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    //抽象方法: 创建Bean
    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition,Object[] args) throws BeansException;

    @Override
    public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
        this.embeddedValueResolvers.add(valueResolver);
    }

    //使用字符串解析器解析字符串，一般用于@Value中的${}
    @Override
    public String resolveEmbeddedValue(String value) {
        String result = value;
        for (StringValueResolver resolver : this.embeddedValueResolvers) {
            result = resolver.resolveStringValue(result);
        }
        return result;
    }

    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor){
        this.beanPostProcessors.remove(beanPostProcessor);
        this.beanPostProcessors.add(beanPostProcessor);
    }

    /**
     * 返回将应用于此beanfactory创建的bean的BeanPostProcessors列表。
     */
    public List<BeanPostProcessor> getBeanPostProcessors() {
        return this.beanPostProcessors;
    }

    public ClassLoader getBeanClassLoader() {
        return this.beanClassLoader;
    }

}